package controllers
/*********************************************************/
/****************本文档中的程序用于控制设备池中的设备************/
/*********************version:1.0*************************/
/****Copyright (c) 2014年 许剑华. All rights reserved******/
/*********************************************************/

import (
	//"container/list"
	"time"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/gorilla/websocket"
	"encoding/json"
	."smart_home/lib"
	"log"
	"strconv"
)

//用于描述连接池中设备的数据结构，连接描述符
type DeviceScript struct {
	Mac 				string				//设备的macf地址
	//ConnTime 			string
	IsBusy				int					//设备是否处于忙的状态
	Conn 				*websocket.Conn // websocket连接的句柄
	CodeTime			*CodeTimeType	//用于描述红外设备时，关于同信得数据
	Status				[] string		//当前设备人状态
	Temperature			int				//当前设备人温度及湿度
	Mask				int
	UnixTime			int64
}

type MsgScript struct {
	Data     []byte
	Mac      string
}
//设备加入websocket连接池
func Join(ws *websocket.Conn,mac string) {
	subscribe <- DeviceScript{Mac: mac, Conn: ws,Status : make([]string,3),Temperature:0}//加入信道
}
//设备离开websocket连接池
func Leave(mac string) {
	unsubscribe <- mac				//加入信道
}

//创建变量
var (
	// 加入连接池的数据信道
	subscribe = make(chan DeviceScript, 1000)
//	更新温度及湿度的信道
	update_temperature = make(chan DeviceScript, 1000)
//	更新开关的信道
	update_switch = make(chan DeviceScript, 1000)
	//设备掉线的信道
	unsubscribe = make(chan string, 1000)

//	改变设备状态的信道
	Change_device_status = make(chan REQ_RESP_Type, 1000)
//用于存储连接数据的连接池
	devices = make(map[string] DeviceScript)
//用于要发送信息的连接池
	send_channel = make(chan MsgScript, 1000)
)
//将设备加入到连接池
func addDevice(device DeviceScript){
	device.Status = make([]string,3)
	devices[device.Mac] = device;
}
//替换连接池中的连接
func replaceDevice(device DeviceScript){

	old_device:=devices[device.Mac]
	fmt.Println("old_device",old_device)
//	if err := old_device.Conn.Close(); err != nil {
//		//return err
//		fmt.Println("close conn srror")
//	}
	devices[device.Mac] = device;

}
//将更新温度和湿度的事件加入到信道中
//@param mac  string   设备的mac地址
//@param int  temperature   温度及湿度
func UpdateTemperature(mac string ,temperature int,time int64){
	update_temperature <- DeviceScript{Mac:mac,Temperature:temperature,UnixTime:time}
}

func UpdateSwitchStatus(mac string ,data REQ_RESP_Type,time int64){
//	status := make([]string,4)
//	if dataMask & 0x01 == 1{
//		status[0] = "1"
//	}
//	if Mask & 0x02 == 1{
//			status[1] = "1"
//	}
//	if Mask & 0x04 == 1{
//			status[2] = "1"
//	}
//
//	status[3] ==
	op ,err:= strconv.ParseInt(data.OpType,10,32)
	if err == nil{
		update_switch <- DeviceScript{Mac:mac,Mask:data.Mask+(((int(op)&0x01))<<8),UnixTime:time}
	}else{
		//update_switch <- DeviceScript{Mac:mac,Mask:data.Mask,UnixTime:time}
	}
}
//将更新的温度和湿度数据加到连接描述符中
//@param device  DeviceScript   设备的连接描述符
func updateTemperature(device DeviceScript){
	old_device:=devices[device.Mac]
	old_device.Temperature = device.Temperature
	old_device.UnixTime = device.UnixTime
	devices[device.Mac] = old_device

}

//将开关状态加到连接描述符中
//@param device  DeviceScript   设备的连接描述符
func updateSwitch(device DeviceScript){
	old_device:=devices[device.Mac]
	old_device.Mask = device.Mask
	old_device.UnixTime = device.UnixTime

	devices[device.Mac] = old_device

}

//将开关状态加到连接描述符中
//@param device  DeviceScript   设备的连接描述符
func GetSwitchStatus(Mac string)(Mask int){
//	status :=devices[Mac].Status
//	for i,v := range status{
//		if v == "1"{
//			Mask += 1<<uint(i)
//		}
//	}
	return devices[Mac].Mask
}
//客户端从连接池中获取红外设备的温度级湿度
//@param mac  string   设备的mac地址
func Get_Temperature(mac string) (int,bool){
	device ,ok:= devices[mac]
	var temperature int
	if ok {
		temperature = device.Temperature
	}else{
		temperature = 0
	}
	return temperature,ok
}
//用户将连接从连接池中移除
//@param mac  string   设备的mac地址
func removeDevice(mac string){
	delete(devices, mac)
}

//将连接从连接池中取出
//@param mac  string   设备的mac地址
func GetWs(mac string) (ws *websocket.Conn){
	return devices[mac].Conn
}
//向终端设备发送命令
//@param mac  string   设备的mac地址
//@param data  interface   设备的mac地址
func SendCmd(mac string,data REQ_RESP_Type)(error){
	//var resp_code REQ_RESP_Type
//
//	device,ok := devices[mac]
//	if ok{
//		b, err := json.Marshal(data)
//		if err != nil{
//			return ResponeType{PARA_JSON_ERROR,mac,INVALID}
//		}
//		fmt.Println("b:",string(b))
//		if err := device.Conn.WriteMessage(websocket.TextMessage,b ); err != nil {
//			fmt.Printf("send error",err)
//			return ResponeType{OPERATION_ERROR,mac,INVALID}
//		}
//		//fmt
//		fmt.Println("send ok")
//		return ResponeType{OPERATION_CHECK,mac,INVALID}
//	}else{
//		return ResponeType{OFFLONE,mac,INVALID}
//	}
	b, err := json.Marshal(data)
	fmt.Println("b",data)
	msg := MsgScript{Data:b,Mac:data.Mac}
	send_channel <- msg
	return err
}


//将设备状态改变事件加入到信道中
//@param data  REQ_RESP_Type   改变的参数
func Send_change_status(data REQ_RESP_Type){
	Change_device_status <- data
}
//将状态的改变写入到连接的描述符中
//@param data  REQ_RESP_Type   改变的参数
func ChangeStatus(data REQ_RESP_Type){

	switch data.DeviceType {
	case DEVICE_REMOTE:
		//devices[data.Mac].Status
		devices[data.Mac].Status[0] = data.OpType
		devices[data.Mac].CodeTime.IRFRQ = data.IRFRQ//new(CodeTimeType)//{Load0:data.CodeTime.Load0,Load1:data.CodeTime.Load1,High:data.CodeTime.High,Low:data.CodeTime.Low}
		devices[data.Mac].CodeTime.TimeScale = data.TimeScale
	case DEVICE_SWITCH:
		if data.Mask & 0x01 == 1{
			devices[data.Mac].Status[data.Mask] = data.OpType
		}
		if data.Mask & 0x02 == 1{
			devices[data.Mac].Status[data.Mask] = data.OpType
		}
		if data.Mask & 0x04 == 1{
			devices[data.Mac].Status[data.Mask] = data.OpType
		}
		//devices[data.Mac].Status[data.Mask] = data.OpType

	}


}



//连接池的事件处理中心
func device_pool() {
	for {
		select {
		case dev := <-subscribe:
			fmt.Printf("chatroom subscribe event\n")
			if !isDeviceExist(dev.Mac) {
				//addChannel()
				//subscribers.PushBack(sub) // Add user to the end of list.
				addDevice(dev)
				//isDeviceExist("3c:15:c2:df:92:80")
			} else {
				beego.Info("Old device:", dev.Mac, ";WebSocket:", dev.Conn != nil)
				replaceDevice(dev)
			}
		case event := <-update_temperature:            //更新室内温度

			go updateTemperature(event)

		case device := <-update_switch:            //更新室内温度

			go updateSwitch(device)
		case undev := <-unsubscribe:
			fmt.Println("设备掉线")
			removeDevice(undev)
		case send_data := <-send_channel:
			fmt.Println("send_channel")
			go sendJson(send_data.Data,devices[send_data.Mac])
		case status := <- Change_device_status:
			//ChangeStatus(status)
			fmt.Println("改变状态",status)
			//go UpdateSwitchStatus(status.Mac,status)
		}
	}
}
//调用启动函数
func init() {
	go device_pool()
	go AutoControl()
	go AutoTimer()
	go CheckTimer()
}
//查询设备是否在连接池中
//@param mac  string   设备的mac地址
func isDeviceExist(mac string) bool {

	data, ok := devices[mac]
	if ok {
		fmt.Println("Found device", data, "with mac:",mac)
		return true
	} else {
		fmt.Println("Did not find device with mac",mac)
		return false
	}
}

//向设备发送json数据
//@param data  []byte   要发送的json数据序列化后的字节流
//@param ws  websocket.Conn   websocket句柄
func sendJson(data []byte,device DeviceScript)(bool){
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Runtime error caught: %v", r)
		}
	}()
	if device.Conn == nil{
		fmt.Println("device.Conn is nil")
		return false
	}
	fmt.Println("send json data",string(data))
	if err := device.Conn.WriteMessage(websocket.TextMessage, data); err != nil {
		fmt.Println("herat err",err)
		return false
	}
	return true
}
//响应设备的心跳包
//@param data  REQ_RESP_Type   响应的数据类型
//@param ws  websocket.Conn   websocket句柄
func ResponeHeart(data REQ_RESP_Type) {
	if isDeviceExist(data.Mac) {
		err := 	SendCmd(data.Mac,REQ_RESP_Type{RespCode:INVALID,Mac:data.Mac,Model:data.Model,DeviceType:data.DeviceType,IP:INVALIDS,Port:INVALID,ProductName:INVALIDS,TimeScale:INVALID,IRFRQ:INVALID,OpType:INVALIDS,Mask:INVALID})

		if err != nil {
			beego.Error("Fail to marshal event:", err)
			return
		}
		//sendJson(respone_data,devices[data.Mac])
	}else {
		//respone_data , err := json.Marshal(HeartType{mac, OpType_INVALID, DEVICE_HEART, RES_REGISTER, 0})
		//respone_data , err := json.Marshal(REQ_RESP_Type{RespCode:RES_REGISTER,Mac:data.Mac,Model:data.Model,DeviceType:data.DeviceType,IP:INVALIDS,Port:INVALID,ProductName:INVALIDS,TimeScale:INVALID,IRFRQ:INVALID,OpType:INVALIDS,Mask:INVALID})
		err := 	SendCmd(data.Mac,REQ_RESP_Type{RespCode:RES_REGISTER,Mac:data.Mac,Model:data.Model,DeviceType:data.DeviceType,IP:INVALIDS,Port:INVALID,ProductName:INVALIDS,TimeScale:INVALID,IRFRQ:INVALID,OpType:INVALIDS,Mask:INVALID})

		if err != nil {
			beego.Error("Fail to marshal event:", err)
			return
		}
	}
}

//获取本服务器的连接池中的设备
//@return   map[string] DeviceScript   描述符字典

func GetOnlineDevice()(map[string] DeviceScript){
	var device_list = devices
	return device_list
}


func  CheckTimeOut(){
	fmt.Println("超时检查")
	for mac,device := range(devices){
		if (time.Now().Unix() -  device.UnixTime) > 40{
			fmt.Println("设备超时 mac:",mac)
			Leave(mac)
		}
	}
}
